﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using GameLibrary;
using GameLibrary.Unit;
using GameLibrary.Map;

namespace UserInterface.Presenters
{
    using Model;
    using Helpers.Graph;

    [Serializable]
    public class GameMapRangeFinder
    {
        private GameMapElement[,] Array;

        public GameMapRangeFinder(GameMapElement[,] array)
        {
            this.Array = array;
        }

        internal IEnumerable<Position> GetValidAttackPositions(
                            UnitInfo unit,
                            Position upperLeftCorner,
                            int gridHeight,
                            int gridWidth)
        {
            Graph graph = new CreateGraphFrom2DArray(
                                    this.Array,
                                    unit.Location,
                                    GetArrayWith1s()).Create();

            GraphNode from = GetGraphNodeWithSamePosition(graph, unit.Location);

            var nodesWithInRange = new Dijkstra_ShortPathAlgorithm_1959(
                                        graph,
                                        from,
                                        unit.Template.AttackRange).GetResult();

            return from node in nodesWithInRange.GraphNodes
                   where node.Position != (unit.Location - upperLeftCorner)
                   select node.Position + upperLeftCorner;
        }

        private GraphNode GetGraphNodeWithSamePosition(Graph graph, Position pos)
        {
            return (from node in graph.GraphNodes
                    where node.Position == pos
                    select node).First();
        }

        private double[,] GetArrayWith1s()
        {
            double[,] array = new double[this.Array.GetLength(0), 
                                         this.Array.GetLength(1)];

            for (int i = 0; i < array.GetLength(0); i++)
                for (int j = 0; j < array.GetLength(1); j++)
                    array[i, j] = 1;

            return array;
        }

        internal IEnumerable<Position> GetValidExplorePosition(
            UnitInfo unit,
            Position upperLeftCorner)
        {
            Position regionUnitAt = MapHelper.FindRegion(unit.Location);

            for (int i = -1; i < 2; i++)
                for (int j = -1; j < 2; j++)
                {
                    Position pos = new Position(i, j);
                    if (pos.X == 0 && pos.Y == 0)
                        continue;
                    foreach (Position p in GetValidRegionPosition(pos))
                        yield return p;
                }
        }

        private IEnumerable<Position> GetValidRegionPosition(Position pos)
        {
            for (int i = 0; i < GMHelper.RegionWidth; i++)
                for (int j = 0; j < GMHelper.RegionHeight; j++)
                {
                    Position position = new Position(i, j) + pos;
                    if (IsPositionWithinMapRange(position))
                        yield return position;
                }
        }

        private bool IsPositionWithinMapRange(Position pos)
        {
            if (pos.IsLessThanZero())
                return false;

            if (pos.X > this.Array.GetLength(0)
                || pos.Y > this.Array.GetLength(1))
                return false;

            return true;
        }

        internal IEnumerable<Position> GetValidMovePosition(
            UnitInfo unit,
            Position upperLeftCorner,
            int gridHeight,
            int gridWidth)
        {
            Graph graph = new CreateGraphFrom2DArray(this.Array, 
                                                     unit.Location)
                                       .Create();

            GraphNode startNode = GetGraphNodeWithSamePosition(graph, unit.Location);

            var nodesWithinRange = new Dijkstra_ShortPathAlgorithm_1959(
                                                graph,
                                                startNode,
                                                unit.Current.AP).GetResult();

            return from node in nodesWithinRange.GraphNodes
                   where node.Position != (unit.Location - upperLeftCorner)
                   select node.Position + upperLeftCorner;
        }      

    }
}
